An intermediate language-type model can be used to support diverse source code programming languages for operation by an execution engine. Compilers may be developed to emit intermediate language code output from source code written in one or more programming languages. In some circumstances, the intermediate language code is directly interpreted by the execution engine within a run time environment. In other circumstances, the intermediate language code may also be compiled (e.g., by a Just-In-Time (JIT) compiler) to convert intermediate language code input into native (i.e., platform dependent) machine code for a given system. To support diverse high-level languages, an intermediate language may support a wide variety of high-level language constructs. An example of an intermediate language-type programming language includes the COM+ (Component Object Model Plus) intermediate language.
Executing software embodied in intermediate language code within an execution engine, however, presents the possibility of executing untrusted code (e.g., code for which the author has not been authenticated). Untrusted code may intentionally attack or inadvertently corrupt the runtime environment in which the code executes.
One opportunity for such attacks or corruption is presented by high-level language “typing” constructs, such as casting. Casting is a program action that converts a value or object from one type to another. For example, a variable of “floating-point” type may be cast to “integer” type. Each programming language has specific rules defining how a cast may occur. A programmer can perform a cast directly, or the language processor can perform the cast at processing time. Improper use of casting, however, may result in a program operation intended for a value having a first type being performed on a value having an incompatible type. In some cases, such improper use of casting may cause a program to crash or to otherwise corrupt the runtime environment.
Another approach for enforcing type safety has involved prohibiting the execution of certain high-level constructs, such as pointers, nested pointers, value classes, and RefAny's, that may introduce execution problems, such as type mismatches and dangling pointers. As such, existing approaches do not pass code containing such constructs for execution.
Attempts to prevent such typing problems have introduced a verification process that imposes strict typing rules on incoming program code and verifies that the received program code is “type safe”, thereby preventing execution errors (or attacks) caused by type mismatches, dangling pointers, etc. Existing approaches for achieving type safety, however, have been unnecessarily restrictive, thereby limiting the support for various high-level language constructs in the original source code.